using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Drawing.Imaging;

namespace Woz
{
    public partial class EditScreenTransitionsCanvas : UserControl
    {
        /// <summary>
        /// default constructor
        /// </summary>
        public EditScreenTransitionsCanvas()
        {
            // build the user interface objects
            InitializeComponent();

            // call our reset
            this.Reset();
        }

        /// <summary>
        /// resets the control to its original state
        /// </summary>
        public void Reset()
        {
            // clear all the controls in the flowlayout
            this.mFlowLayoutPanel.Controls.Clear();
            
            // tell the transition panel to reset
            this.mTransitionPanel.Reset();

            // add a callback so we know when a transition has been added
            Woz.ScreenManager.Instance.ScreenTransitionAdded -= this.cScreenTransitionAdded;
            Woz.ScreenManager.Instance.ScreenTransitionAdded += this.cScreenTransitionAdded;

            // toggle the mode back into the linear
            this.mUseCustomTransitions = true;
            this.ToggleMode();
        }

        /// <summary>
        /// gets any pending screens from the screen manager and puts them in the flowlayout
        /// </summary>
        public void RetrieveScreensFromScreenManager()
        {
            if (Woz.DynamicVariables.Instance.UsingCustomTransitions)
            {
                this.mUseCustomTransitions = false;
                this.ToggleMode();
            }

            // add any new screen thumbnails to the edit screen transitions canvas
            foreach (Woz.Screen screen in Woz.ScreenManager.Instance.Screens)
            {
                if (screen.Hidden)
                {
                    continue;
                }

                if (screen.TransitionsThumbnail.Parent == null)
                {
                    if (screen.TransitionsThumbnail.Tag == null)
                    {
                        this.AddScreenThumbnailToFlowLayout(screen.TransitionsThumbnail);
                    }
                    else
                    {
                        this.AddScreenThumbnailToTransitionPanel(screen.TransitionsThumbnail);
                    }
                }
            }
        }

        /// <summary>
        /// adds the passed in screenthumbnail to this canvas
        /// </summary>
        /// <param name="pScreenThumbnail"></param>
        public void AddScreenThumbnail(Woz.ScreenThumbnail pScreenThumbnail)
        {
            // if a thumbnail gets added to this control it first goes to the unlinked screens flowlayout
            this.AddScreenThumbnailToFlowLayout(pScreenThumbnail);
        }

        internal void EnterEditScreenTransitions()
        {
            this.mTransitionPanel.EnterTransitionPanel();
        }

        internal void LeaveEditScreenTransitions()
        {
            this.mTransitionPanel.LeaveTransitionPanel();
        }

        /// <summary>
        /// adds the passed in screenthumbnail to the flowlayout panel
        /// </summary>
        /// <param name="pScreenThumbnail">screenthumbnail to add</param>
        private void AddScreenThumbnailToFlowLayout(Woz.ScreenThumbnail pScreenThumbnail)
        {
            // add some callbacks to this thumbnail
            pScreenThumbnail.MouseDown += this.cMouseDownOnThumbnailInFlowLayout;
            pScreenThumbnail.MouseUp += this.cMouseUpOnThumbnailInFlowLayout;
            pScreenThumbnail.MouseMove += this.cMouseMoveOnThumbnailInFlowLayout;

            // remove the transition panel callbacks from this thumbnail
            pScreenThumbnail.MouseDown -= this.mTransitionPanel.cScreenThumbnailMouseDown;
            pScreenThumbnail.MouseUp -= this.mTransitionPanel.cScreenThumbnailMouseUp;
            pScreenThumbnail.MouseMove -= this.mTransitionPanel.cScreenThumbnailMouseMove;

            // take the top margin off of the screen thumbnail
            pScreenThumbnail.Margin = new Padding(0, 0, 9, 0);

            // clear the tag
            pScreenThumbnail.Tag = null;

            // turn the label off instructing the user to drag and drop transitions
            this.mLabelDragTransitions.Visible = false;

            // finally add this thumbnail to the flowlayout panel that represents unlinked screens
            this.mFlowLayoutPanel.Controls.Add(pScreenThumbnail);
        }

        /// <summary>
        /// adds the passed in screenthumbnail to the transition panel
        /// </summary>
        /// <param name="pScreenThumbnail">screenthumbnail to add</param>
        private void AddScreenThumbnailToTransitionPanel(Woz.ScreenThumbnail pScreenThumbnail)
        {
            // add the transition panel callbacks to this thumbnail
            pScreenThumbnail.MouseDown += this.mTransitionPanel.cScreenThumbnailMouseDown;
            pScreenThumbnail.MouseUp += this.mTransitionPanel.cScreenThumbnailMouseUp;
            pScreenThumbnail.MouseMove += this.mTransitionPanel.cScreenThumbnailMouseMove;
            pScreenThumbnail.DoubleClick += this.mTransitionPanel.cScreenThumbnailDoubleClick;

            // take the top margin off of the screen thumbnail
            pScreenThumbnail.Margin = new Padding(0, 0, 9, 0);

            // turn the label off instructing the user to drag and drop transitions
            this.mLabelDragTransitions.Visible = false;

            // finally add this thumbnail to the flowlayout panel that represents unlinked screens
            this.mTransitionPanel.AddScreenThumbnail(pScreenThumbnail, false);
        }

        /// <summary>
        /// removes the passed in screenthumbnail from the flowlayout panel
        /// </summary>
        /// <param name="pScreenThumbnail">screenthumbnail to remove</param>
        private void RemoveScreenThumbnailFromFlowLayout(Woz.ScreenThumbnail pScreenThumbnail)
        {
            // make sure this thumbnail exists in the flowlayout
            if (!this.mFlowLayoutPanel.Controls.Contains(pScreenThumbnail))
            {
                return;
            }

            // this thumbnail definetly exists in the flowlayout so proceed to remove it

            // remove our callbacks from this control
            pScreenThumbnail.MouseDown -= this.cMouseDownOnThumbnailInFlowLayout;
            pScreenThumbnail.MouseUp -= this.cMouseUpOnThumbnailInFlowLayout;
            pScreenThumbnail.MouseMove -= this.cMouseMoveOnThumbnailInFlowLayout;

            // add the transition panel callbacks to this thumbnail
            pScreenThumbnail.MouseDown += this.mTransitionPanel.cScreenThumbnailMouseDown;
            pScreenThumbnail.MouseUp += this.mTransitionPanel.cScreenThumbnailMouseUp;
            pScreenThumbnail.MouseMove += this.mTransitionPanel.cScreenThumbnailMouseMove;
            pScreenThumbnail.DoubleClick += this.mTransitionPanel.cScreenThumbnailDoubleClick;

            // and finally remove it
            this.mFlowLayoutPanel.Controls.Remove(pScreenThumbnail);
        }

        /// <summary>
        /// toggles the current mode of the canvas between linear and custom transitions
        /// </summary>
        private void ToggleMode()
        {
            // toggle the mode member
            Woz.DynamicVariables.Instance.UsingCustomTransitions = this.mUseCustomTransitions = !this.mUseCustomTransitions;

            // check if were now using linear transitions
            if(this.mUseCustomTransitions)
            {
                // update the toggle button
                this.mButtonToggleMode.Text = "Use Linear Transitions";
                this.mButtonToggleMode.Location = new Point(this.Width - this.mButtonToggleMode.Width - 8, this.mTabControlUnlinkedScreens.Top + 3);
                this.mButtonToggleMode.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;

                // toggle the appropriate controls
                this.mLabelUsingLinear.Visible = false;
                this.mTransitionPanel.Visible = true;
                this.mTabControlUnlinkedScreens.Visible = true;
                this.mFlowLayoutPanel.Visible = true;

                // check if we need to show the message telling them to add transitions
                if (this.mTransitionPanel.Controls.Count <= 0)
                {
                    this.mLabelDragTransitions.Visible = true;
                }

                // throw the focus off the button
                this.mTabControlUnlinkedScreens.Focus();
            }

            else
            {
                // update the toggle button
                this.mButtonToggleMode.Text = "Define Custom Transitions";
                this.mButtonToggleMode.Location = new Point(Woz.Utilities.Instance.CenterInParent(this.mButtonToggleMode, Woz.Utilities.Axis.X), this.mLabelUsingLinear.Bottom + 10);
                this.mButtonToggleMode.Anchor = AnchorStyles.Top;

                // toggle the appropriate controls
                this.mLabelUsingLinear.Visible = true;
                this.mTransitionPanel.Visible = false;
                this.mTabControlUnlinkedScreens.Visible = false;
                this.mFlowLayoutPanel.Visible = false;
                this.mLabelDragTransitions.Visible = false;

                // throw the focus off the button
                this.mLabelUsingLinear.Focus();
            }
        }

        /// <summary>
        /// gets called when a screenthumbnail in the flowlayout gets a mouse down
        /// </summary>
        /// <param name="pSender">screenthumbnail that fired the event</param>
        /// <param name="pEventArgs">mouse event args</param>
        private void cMouseDownOnThumbnailInFlowLayout(object pSender, MouseEventArgs pEventArgs)
        {
            this.mDragging = true;
        }

        private bool mDragging;

        /// <summary>
        /// gets called when a screenthumbnail in the flowlayout gets a mouse up
        /// </summary>
        /// <param name="pSender">screenthumbnail that fired the event</param>
        /// <param name="pEventArgs">mouse event args</param>
        private void cMouseUpOnThumbnailInFlowLayout(object pSender, MouseEventArgs pEventArgs)
        {
            // check if we let go inside of the transition panel
            if (this.mTransitionPanel.DrawSemiTransparentScreenThumbnail)
            {
                // cast the sender to a screenthumbnail
                Woz.ScreenThumbnail screenThumbnail = (Woz.ScreenThumbnail)pSender;

                // first remove it from the flow layout
                this.RemoveScreenThumbnailFromFlowLayout(screenThumbnail);

                // add this thumbnail to the transition panel
                this.mTransitionPanel.AddScreenThumbnail(screenThumbnail, true);

                // turn the label off instructing the user to drag and drop transitions
                this.mLabelDragTransitions.Visible = false;

                // turn the label off instructing the user to drag and drop transitions
                this.mLabelDragTransitions.Visible = false;

                // turn the flag off now that were done drawing
                this.mTransitionPanel.DrawSemiTransparentScreenThumbnail = false;
            }

            // kill the semi transparent image in the transitionpanel
            this.mTransitionPanel.SemiTransparentImageOfScreenThumbnail = null;
            this.mDragging = false;
        }

        /// <summary>
        /// gets called when a screenthumbnail in the flowlayout gets a mouse move
        /// </summary>
        /// <param name="pSender">screenthumbnail that fired the event</param>
        /// <param name="pEventArgs">mouse event args</param>
        private void cMouseMoveOnThumbnailInFlowLayout(object pSender, MouseEventArgs pEventArgs)
        {
            Woz.ScreenThumbnail thumbnail = pSender as Woz.ScreenThumbnail;

            // make sure there is a semi transparent image in the transitionpanel before we continue
            //if (this.mTransitionPanel.SemiTransparentImageOfScreenThumbnail == null)
            if(!this.mDragging)
            {
                return;
            }

            // calculate the actual mouse position within ourselves
            Point mousePosition = new Point(
                                        (this.mFlowLayoutPanel.Left + thumbnail.Left + pEventArgs.X),
                                        (this.mFlowLayoutPanel.Top + thumbnail.Top + pEventArgs.Y));

            // check if this mouse position is up into the transitionpanel
            if (mousePosition.Y < this.mTransitionPanel.Height)
            {
                // check if this is the first time were entering this area
                if (this.mFirstTimeEnteringTransitionPanel)
                {
                    // we are now dragging a screenthumbnail into the transitionpanel

                    // create a bitmap image of this control that we just put the mouse down on
                    Bitmap bitmap = new Bitmap(Woz.ScreenThumbnail.ScreenThumbnailSize.Width, Woz.ScreenThumbnail.ScreenThumbnailSize.Height);
                    ((Control)pSender).DrawToBitmap(bitmap, new Rectangle(0, 0, Woz.ScreenThumbnail.ScreenThumbnailSize.Width, Woz.ScreenThumbnail.ScreenThumbnailSize.Height));
                    //bitmap.Save("TEST.BMP", ImageFormat.Bmp);
                    
                    // set this bitmap as the one to semi transparently draw in the transition panel
                    this.mTransitionPanel.SemiTransparentImageOfScreenThumbnail = bitmap;

                    // turn the flag on in the transitionpanel so it knows to draw the transition panel
                    this.mTransitionPanel.DrawSemiTransparentScreenThumbnail = true;

                    // turn our flag off so we dont come back in here
                    this.mFirstTimeEnteringTransitionPanel = false;
                }

                // send this position to the transition panel so it knows where to draw the screenthumbnail
                this.mTransitionPanel.MousePositionForSemiTransparentScreenThumbnail = mousePosition;

                // tell the transitionpanel to invalidate
                this.mTransitionPanel.Invalidate();
            }

            // and check if the mouse position is not up into the transitionpanel
            else
            {
                this.mFirstTimeEnteringTransitionPanel = true;

                // were not mouse over the transitionpanel so turn the drawing flag off the transitionpanel
                this.mTransitionPanel.DrawSemiTransparentScreenThumbnail = false;
            }
        }

        private bool mFirstTimeEnteringTransitionPanel;

        /// <summary>
        /// gets called the toggle mode button gets clicked
        /// </summary>
        /// <param name="pSender">toggle mode button</param>
        /// <param name="pEventsArgs">empty event args</param>
        private void cToggleModeButtonClicked(object pSender, EventArgs pEventsArgs)
        {
            // just call our method to toggle
            this.ToggleMode();
        }

        /// <summary>
        /// gets called when a transition is added to the transitionpanel
        /// </summary>
        /// <param name="pSender">the transitionpanel</param>
        /// <param name="pEventArgs">empty event args</param>
        private void cScreenTransitionAdded(object pSender, EventArgs pEventArgs)
        {
            // turn the label off instructing the user to drag and drop transitions
            //this.mLabelDragTransitions.Visible = false;

            // unsubscribe this event
            Woz.ScreenManager.Instance.ScreenTransitionAdded -= this.cScreenTransitionAdded;
        }

        /// <summary>
        /// flag whether or not we are using linear mode
        /// </summary>
        private bool mUseCustomTransitions;
    }
}
